#include "Parser.h"
using std::string;

Parser::Parser() {
	archivo = NULL;
	leeDeStandard = false;
}

bool Parser::aperturaErronea() const {
	return archivo->fail();
}

std::istream* Parser::getArchivo() const {
	return archivo;
}

void Parser::leerDeStandard() {
	archivo = &std::cin;
	leeDeStandard = true;
}

/* Dado el string que representa las piezas de una fila,
 * las ubica en el tablero en la posicion correspondiente. */

void Parser::armarFila(const string& unaFila,
					   Tablero* unTablero,
					   int numeroFila) {
	Posicion posicion;
	int numeroColumna = 0;
	int offset = 0;
	char piezaACrear;
	int fin;
	tColor color;
	posicion.setY(numeroFila);
	// Para salvar el caso de la ultima fila que
	// viene con mas caracteres (por el color).
	fin = (unaFila.length() < 8)? unaFila.length() : 8;
	for (int i = 0; i < fin; i++) {
		piezaACrear = unaFila[i];
		if (islower(piezaACrear))
			color = NEGRO;
		else
			color = BLANCO;
		piezaACrear = toupper(piezaACrear);
		posicion.setX(numeroColumna);
		if(piezaACrear >= 'A') {
			switch(piezaACrear) {
				case PEON:
					unTablero->setPieza(posicion, new Peon(color, posicion));
					break;
				case TORRE:
					unTablero->setPieza(posicion, new Torre(color, posicion));
					break;
				case CABALLO:
					unTablero->setPieza(posicion, new Caballo(color, posicion));
					break;
				case ALFIL:
					unTablero->setPieza(posicion, new Alfil(color, posicion));
					break;
				case REINA:
					unTablero->setPieza(posicion, new Reina(color, posicion));
					break;
				case REY:
					unTablero->setPieza(posicion, new Rey(color, posicion));
					break;
			}
			numeroColumna++;
		} else {
			offset = numeroColumna;
			for (int j = numeroColumna; j < (piezaACrear -'0') + offset; j++) {
				posicion.setX(numeroColumna);
				unTablero->setCasilleroVacio(posicion);
				numeroColumna++;
			}
		}
	}
}

/* Determina si el turno es un enroque. Devuelve NO_ENROQUE si no lo es,
 * CORTO si es un enroque corto o LARGO si es un enroque largo.*/

tEnroque Parser::esEnroque(const string& turno) const {
	int aux = turno.find("0-0-0");
	if (aux >= 0)
		return LARGO;
	aux = turno.find("0-0");
	if (aux >= 0)
		return CORTO;
	return NO_ENROQUE;
}

bool Parser::debePromocionar(const string&  turno) const {
    char caracter = turno.at(turno.length()-1);
	return (caracter >= 'A');
}

/* Dada una cadena que represente el numero de una movida,
 * devuelve el entero que corresponde a dicha modida. */

int Parser::numeroDeMovimiento(string& movimiento) const {
	int encontroEn = movimiento.find('?');
	movimiento = movimiento.substr(0, encontroEn);
	return atoi(movimiento.c_str());
}

tColor Parser::identificarColorInicial() const {
	string fila;
    tColor colorInicial;
	getline(*archivo, fila, '\n');
	// Obtiene el color del siguiente turno.
    colorInicial = (fila[0] == 'w')? BLANCO : NEGRO;
    getline(*archivo, fila, '\n');  // Descarto.
    return colorInicial;
}

/* Parsea cada turno y los procesa sobre un tablero. */

void Parser::leerTurnos(Tablero *tablero) const {
	// false indica que no se desean evaluar posibles movimientos.
	bool evaluarMovimientos = false;
	string linea;
	string turno;
    int encontroEn = 0;
    tColor colorSiguienteTurno = identificarColorInicial();
    int numeroMovimiento;
    int enroque = 0;
    bool promociona;
    while (!(archivo->eof())) {
    	getline(*archivo, linea);
    	encontroEn = 0;
    	while ((encontroEn >= 0) && (linea.length() > 0)) {
    		encontroEn = linea.find(' ');
    		turno = linea.substr(0, encontroEn);
    		linea.erase(0, encontroEn + 1);
    		if (esNumeroDeJugada(turno)) {
    			evaluarMovimientos = this->evaluarMovimientos(turno);

    			if (evaluarMovimientos) {
    				numeroMovimiento = this->numeroDeMovimiento(turno);
    				std::cout << std::endl << "Analisis para movida: "
    												<< numeroMovimiento << std::endl;
    			}
    		}
    		else {
    			enroque = esEnroque(turno);
    			promociona = debePromocionar(turno);
    			tablero->procesarTurno(turno, colorSiguienteTurno, evaluarMovimientos,
    																enroque, promociona);
    			colorSiguienteTurno = (colorSiguienteTurno == BLANCO)? NEGRO : BLANCO;
    		}
    	}
    }
}

/* Dada una cadena, identifica si se trata del numero de una jugada. */

bool Parser:: esNumeroDeJugada(const string& turno) const {
	int aux = turno.find('.');
	return (aux >= 0)? true : false;
}

/* Dada una cadena, identifica si se desean evaluar movimientos. */

bool Parser:: evaluarMovimientos(const string& turno) const {
	int aux = turno.find('?');
	return (aux >= 0)? true : false;
}

void Parser::abrirArchivo(char* path) {
	archivo = new std::ifstream(path);
	leeDeStandard = false;
}

Parser::~Parser() {
	if (!leeDeStandard)
		delete (archivo);
}
